﻿
#region 文件信息
/*----------------------------------------------------------------
// 
// 文件名称：	
// 文件功能描述：	
// 设计要求：	
//
// 文 件 名：    DoNotifyGenerator
// 创建者：      杨程
// 创建日期：	    2023/2/7 14:12:14

//----------------------------------------------------------------*/
#endregion

using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Text;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;



namespace Vampirewal.Core.SourceGeneratorMvvm.Generators;

public class DoNotifySyntaxReceiver : ISyntaxReceiver
{
    public List<AttributeSyntax> CandidateClasses { get; } = new List<AttributeSyntax>();
    public void OnVisitSyntaxNode(SyntaxNode syntaxNode)
    {
        if (syntaxNode is AttributeSyntax cds && cds.Name is IdentifierNameSyntax identifierName && identifierName.Identifier.ValueText == "DoNotifyProperty")
        {
            CandidateClasses.Add(cds);
        }
    }
}

/// <summary>
/// 
/// </summary>
[Generator]
public partial class DoNotifyGenerator : ISourceGenerator
{
    public void Execute(GeneratorExecutionContext context)
    {
        var syntaxReceiver = (DoNotifySyntaxReceiver)context.SyntaxReceiver;
        var attributeSyntaxList = syntaxReceiver.CandidateClasses;

        if (attributeSyntaxList.Count == 0)
        {
            return;
        }

        List<string> ClassName = new List<string>();

        foreach (var attributeSyntax in attributeSyntaxList)
        {
            

            // 找到class，并且判断一下是否有parital字段
            var classDeclarationSyntax = attributeSyntax.FirstAncestorOrSelf<ClassDeclarationSyntax>();
            if (classDeclarationSyntax == null || !classDeclarationSyntax.Modifiers.Any(m => m.IsKind(SyntaxKind.PartialKeyword)))
            {
                continue;
            }

            //classDeclarationSyntax.BaseList

            // 找到namespace
            var namespaceDeclarationSyntax = classDeclarationSyntax.FirstAncestorOrSelf<BaseNamespaceDeclarationSyntax>();
            if (ClassName.Contains(classDeclarationSyntax.Identifier.ValueText))
            {
                continue;
            }

            // 找到field
            var fieldDeclarationList = classDeclarationSyntax.Members.OfType<FieldDeclarationSyntax>().ToList();
            if (fieldDeclarationList.Count == 0)
            {
                continue;
            }

            ClassName.Add(classDeclarationSyntax.Identifier.ValueText);

            StringBuilder sb = new StringBuilder();

            sb.AppendLine("// <auto-generated/>");
            sb.AppendLine("#pragma warning disable");
            sb.AppendLine("#nullable enable");
            sb.AppendLine();
            sb.AppendLine($"namespace {namespaceDeclarationSyntax.Name.ToString()}");
            sb.AppendLine("{");
            sb.AppendLine($"    public partial class {classDeclarationSyntax.Identifier.Text}");
            sb.AppendLine("    {");

            foreach (var field in fieldDeclarationList)
            {
                var type = field.Declaration.Type.ToString();

                

                foreach (var declarationVariable in field.Declaration.Variables)
                {
                    var name = SyntaxUtils.GetName(declarationVariable);

                    var propertyName = Utils.ConvertToPascal(name, "");

                    sb.AppendLine();
                    sb.AppendLine($"        /// <summary>");
                    sb.AppendLine($"        /// <inheritdoc cref=\"{name}\"/>");
                    sb.AppendLine($"        /// </summary>");
                    
                    sb.AppendLine($"        public {type} {propertyName} ");
                    sb.AppendLine("        {");
                    sb.AppendLine("            get");
                    sb.AppendLine("            {");
                    sb.AppendLine($"               return {name};");
                    sb.AppendLine("            }");
                    sb.AppendLine("            set");
                    sb.AppendLine("            {");
                    sb.AppendLine($"               On{propertyName}Changing?.Invoke({name},value);");
                    sb.AppendLine($"               {name}=value;");
                    sb.AppendLine($"               On{propertyName}Changed?.Invoke(value);");
                    sb.AppendLine($"               DoNotify();");
                    sb.AppendLine("            }");
                    sb.AppendLine("        }");
                    sb.AppendLine();

                    sb.AppendLine($"        /// <summary>{propertyName}属性变更前 </summary>");
                    sb.AppendLine($"        public Action<{type},{type}> On{propertyName}Changing; ");
                    sb.AppendLine($"        /// <summary>{propertyName}属性变更后 </summary>");
                    sb.AppendLine($"        public Action<{type}> On{propertyName}Changed; ");

                    //sb.AppendLine($"        /// <summary>{propertyName}属性变更前 </summary>");
                    //sb.AppendLine($"        partial void On{propertyName}Changing({type} oldValue,{type} newValue); ");
                    
                    //sb.AppendLine($"        /// <summary>{propertyName}属性变更后 </summary>");
                    //sb.AppendLine($"        partial void On{propertyName}Changed({type} newValue); ");
                    //sb.AppendLine($"        partial void On{propertyName}Changed({type} newValue); ");
                    sb.AppendLine();
                }
            }

            sb.AppendLine("    }");
            sb.AppendLine("}");

            context.AddSource($"{classDeclarationSyntax.Identifier.Text}.g.cs", SourceText.From(sb.ToString(), Encoding.UTF8));
        }
    }

    public void Initialize(GeneratorInitializationContext context)
    {
#if DEBUG
        //Debugger.Launch();
#endif

        context.RegisterForSyntaxNotifications(() => new DoNotifySyntaxReceiver());
    }
}
